import SocketServer
from game import *
import re
import simplejson
import sys
import socket
import inspect


class JSonIO:
	def __init__(self, io):
		self.io = io
		
	def send(self, data):
		try:
			self.io.send(simplejson.dumps(data) + '\n')
		except:
			raise Exception('Unable to encode JSON data %s' % (data) )
	
	def receive(self):
		try:
			self.buffer = ''
			self.buffer = self.io.recv(1024)
			
			while len(self.buffer.split('{')) != len(self.buffer.split('}')):
				self.buffer += self.io.recv(1024)
				
			self.buffer = self.buffer.strip()
		except:
			raise Exception('Unable to decode JSON data %s' % (self.buffer) )
			
		if self.buffer == '': raise ClosedConnection()
		return simplejson.loads(self.buffer)
		
	
#	def get_json_buffer(self):
#		return self.buffer

class ClosedConnection(Exception):
	pass


class RESTClient(socket.socket):
	def __init__(self):
		socket.socket.__init__(self, socket.AF_INET, socket.SOCK_STREAM)
		self.json = JSonIO(self)
		
	def info(self, message):
		for l in message.split('\n'):
			print "client:: " + l
		
	def send_request(self, action, resource, params = {}):
		self.info("action=%s, resource=%s, params=%s" % (action, resource, params))
		request = {'action': action, 'resource': resource, 'params': params}
		self.json.send(request)
		self.response = self.json.receive()


class STDOutLogHandler:
	def handle(self, event):
		for l in event['message'].split('\n'):
			print "server:: " + l


class TreeTool:
	def __init__(self, tree):
		self.tree = tree
	
	def each_leaf_callback(self, callback, obj = None):
		if isinstance(obj, list):
			for k, v in enumerate(obj):
				obj[k] = self.each_leaf_callback(callback, v)
		elif isinstance(obj, dict):
			for i in obj:
				obj[i] = self.each_leaf_callback(callback, obj[i])
		else:
			obj = callback(obj)
		
		return obj
	
	def each_leaf(self, callback = None, obj = None):
		if obj == None: obj = self.tree
		
		if callback != None:
			return self.each_leaf_callback(callback, obj)
		else:
			raise Exception('no callback not supported yet !')


class InterceptoServerHandler(SocketServer.BaseRequestHandler):
	def info(self, message):
		for l in message.split('\n'):
			print "server:: " + l
	
	def handle(self):
		self.json = JSonIO(self.request)
		looptrue= True
		
		while looptrue :
			request = None
			try:
				request = self.json.receive()
				action = request['action']
				resource = request['resource']
				params = request['params']
				
				if resource != 'game/log/tail_channel' and action != 'POST' and resource != 'messages':
					self.info('Receive request: %s' % (request))
					
			except ClosedConnection:
				looptrue = False
				
			except:
				self.info('Unable to parse request: [%s]' % (self.json.buffer))
				self.json.send({'status':500, 'message_error':'Unable to parse request'})
				looptrue = False
			
			if request != None:
				# call method on object if exists
				action_resource = '%s_%s' % (action.lower(), resource.replace('/', '_'))
				if hasattr(self, action_resource):
					response = getattr(self, action_resource)(params)
				else:
					response = self.get_resources(self, resource)
					if action == 'GET':
						normalize = self.normaliz
						response = TreeTool(response).each_leaf(normalize)
					elif action == 'PUT':
						self.params = params
						update = self.update
						TreeTool(response).each_leaf(update)
						response = {'status': 200}
				
				if response == None: response = {}
				if not response.has_key('status'):
					response['status'] = 200
				
				self.json.send(response)
				
				#if resource != 'game/log/tail_channel' or len(response['game']['log']['tail_channel']) != 0:
				#	self.info('Response: %s' % simplejson.dumps(response))
	
	def get_messages(self, params):
		messages = self.game.log.tail(params['start'])
		TreeTool(messages).each_leaf(self.normaliz)
		
		return {'status': 200, 'messages': messages}
	
	def update(self, entity):
#		print type(entity)
		if inspect.ismethod(entity):
			entity(self.params)
#		print self.params
		return entity
	
	def normaliz(self, obj):
		if inspect.ismethod(obj):
			if isinstance(obj, list) or isinstance(obj, dict):
				TreeTool(obj).each_leaf(self.normaliz)
				return obj
			
		if isinstance(obj, int):
			pass
		elif isinstance(obj, str):
			pass
		elif isinstance(obj, unicode):
			pass
		else:
			obj = obj.__repr__()
			print obj
		
		return obj
	
	def post_color(self, params):
		if Card(params['value']).isColour():
			self.game.choose_color(self.player, params['value'])
		else:
			return {'status': 500, 'message_error': 'You cannot choose a color.'}
		return {}
	
	def post_player(self, params):
		if params.has_key('id') and params['id'] <= len(self.game.players):
			self.player = self.game.players[params['id']]
	
	def post_game(self, params):
		if params.has_key('id') and params['id'] <= len(self.server.games):
			self.game = self.server.games[params['id']]
		else:
			self.game = Game()
			self.game.id = len(self.server.games)
			self.server.games.append(self.game)
			self.game.log.add_handler(STDOutLogHandler())
			self.info('Start game with %s players.\n' % (params['players']))
			for i in range(params['players']):
				self.game.add_player(Player())
			self.game.start(params)
		
	#~ def get_player(self, params):
		#~ self.player = self.game.players[params['id']]
	
	#~ def get_game(self, params):
		#~ self.game = self.server.games[params['id']]
	
	def get_resources(self, obj, path):
		if path[0] == '{':
			dict = {}
			splits, next = self.split_collection(path, '{', '}', ',')
			for i in splits:
				subdict = self.get_resources(obj, i + next)
				for k in subdict:
					dict[k] = subdict[k]
			return dict
		
		dict = {}
		m = re.match(r"^([^/]+)/?(.+)?$", path)
		if m != None:
			resource_name = m.group(1)
			nextpath = m.group(2)
			if hasattr(obj, resource_name):
				attr = getattr(obj, resource_name)
				
				if nextpath != None:
					if inspect.ismethod(attr):
						attr = attr()
					
					if isinstance(attr, list):
						m = re.match(r"^([0-9]+)/?(.+)?$", nextpath)
						if m != None:
							id = m.group(1).to_integral()
							nextpath = m.group(2)
							# @todo: not supported yet
							raise Exception('Not supported yet')
						
						dict[resource_name] = []
						for o in attr:
							ret = self.get_resources(o, nextpath)
							if hasattr(o, 'id'): ret['id'] = o.id
							dict[resource_name].append(ret)
					else:
						dict[resource_name] = self.get_resources(attr, nextpath)
				else:
#					dict[resource_name] = self.normalize(attr)
					dict[resource_name] = attr
		else:
			raise Exception('Error while trying to parse resource path')
		
		return dict
	
	def fork_path(self, path):
		pass
	
	def split_collection (self, str, start, end, sep):
		n = len(str)
		i = 0
		last = 1
		depth = 0
		res = []
		while i < n:
			if str[i] == start:
				depth += 1
			elif str[i] == end:
				depth -= 1
			elif depth == 1:
				if str[i] == sep:
					res.append(str[last:i])
					last = i + 1
			if depth == 0:
				break
			i += 1
			
		res.append(str[last:i])
		last = i + 1
		
		return (res, str[last:])
	
#	def normalize(self, obj):
#		if isinstance(obj, list):
#			for k, v in enumerate(obj):
#				obj[k] = self.normalize(v)
#		elif isinstance(obj, dict):
#			for i in obj:
#				obj[i] = self.normalize(obj[i])
#		elif isinstance(obj, int):
#			pass
#		elif isinstance(obj, str):
#			pass
#		else:
#			obj = obj.__repr__()
#		
#		return obj
		

class ThreadedTCPServer(SocketServer.ThreadingMixIn, SocketServer.TCPServer):
	"A ThreadedTCPServer"
	pass

class InterceptoServer(ThreadedTCPServer):
	"""InterceptoServer is threaded TCP Server including game
	data and using InterceptoServerHandler to handle request"
	"""
	def __init__ (self, a):
		ThreadedTCPServer.__init__(self, a, InterceptoServerHandler);
		self.games = []
		